#ifndef RATIONAL_H
#define RATIONAL_H

#include <iostream>
#include <algorithm>
using std::ostream;
using std::swap;

class Rational {
    friend ostream& operator<< (ostream&, const Rational&);

public:
    Rational (int = 1, int = 1);
    virtual ~Rational () {}

    const Rational operator+ (const Rational&) const;
    const Rational operator- (const Rational&) const;
    const Rational operator* (const Rational&) const;
    const Rational operator/ (const Rational&) const;

    Rational & operator+= (const Rational& rhs)
    {
        return (*this = *this + rhs);
    }

    Rational & operator-= (const Rational& rhs)
    {
        return (*this = *this - rhs);
    }

    bool operator== (const Rational& rhs) const
    {
        return (is_signed == rhs.is_signed &&
                num () == rhs.num () && denom () == rhs.num ());
    }

    bool operator!= (const Rational& rhs) const
    {
        return !(*this == rhs);
    }

    bool operator< (const Rational& rhs) const
    {
        return decimal () < rhs.decimal ();
    }

    bool operator> (const Rational& rhs) const
    {
        return rhs < *this;
    }

    bool operator>= (const Rational& rhs) const
    {
        return rhs < *this || *this == rhs;
    }

    bool operator<= (const Rational& rhs) const
    {
        return *this < rhs || *this == rhs;
    }

    void set_numerator (int);
    void set_denominator (int);
    void reduce ();
    int num () const;
    int denom () const;
    double decimal () const;
    Rational abs () const;

    static int gcd (int, int);

private:
    int numerator;
    int denominator;
    bool is_signed;
};

inline Rational abs (const Rational & rhs)
{
    return rhs.abs ();
}

#endif /* end of include guard: RATIONAL_H */
